#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/scrnsaver.h>

/* Default to -1, initialize it when we need it */
static Atom atom_NET_WM_PID = -1;
static Atom atom_NET_WM_NAME = -1;
static Atom atom_WM_NAME = -1;
static Atom atom_WM_CLASS = -1;
static Atom atom_STRING = -1;
static Atom atom_UTF8_STRING = -1;

#define XDO_ERROR 1
#define XDO_SUCCESS 0

/**
 * Find a client window that is a parent of the window given
 */
#define XDO_FIND_PARENTS (0)

/**
 * Find a client window that is a child of the window given
 */
#define XDO_FIND_CHILDREN (1)

/* Arbitrary window property retrieval
 * slightly modified version from xprop.c from Xorg */
unsigned char *xdo_getwinprop(Display *display, Window window, Atom atom,
                              long *nitems, Atom *type, int *size) {
  Atom actual_type;
  int actual_format;
  unsigned long _nitems;
  unsigned long nbytes;
  unsigned long bytes_after; /* unused */
  unsigned char *prop;
  int status;

  status = XGetWindowProperty(display, window, atom, 0, (~0L),
                              False, AnyPropertyType, &actual_type,
                              &actual_format, &_nitems, &bytes_after,
                              &prop);
  if (status == BadWindow) {
    fprintf(stderr, "window id # 0x%lx does not exists!", window);
    return NULL;
  } if (status != Success) {
    fprintf(stderr, "XGetWindowProperty failed!");
    return NULL;
  }

  if (actual_format == 32)
    nbytes = sizeof(long);
  else if (actual_format == 16)
    nbytes = sizeof(short);
  else if (actual_format == 8)
    nbytes = 1;
  else if (actual_format == 0)
    nbytes = 0;

  if (nitems != NULL) {
    *nitems = _nitems;
  }

  if (type != NULL) {
    *type = actual_type;
  }

  if (size != NULL) {
    *size = actual_format;
  }
  return prop;
}

int xdo_window_find_client(Display *display, Window window, Window *window_ret,
                           int direction) {
  /* for XQueryTree */
  Window dummy, parent, *children = NULL;
  unsigned int nchildren;
  Atom atom_wmstate = XInternAtom(display, "WM_STATE", False);

  int done = False;
  while (!done) {
    if (window == 0) {
      return XDO_ERROR;
    }

    long items;
    //    _xdo_debug(xdo, "getwinprop on %lu", window);
    xdo_getwinprop(display, window, atom_wmstate, &items, NULL, NULL);

    if (items == 0) {
      /* This window doesn't have WM_STATE property, keep searching. */
      //      _xdo_debug(xdo, "window %lu has no WM_STATE property, digging more.", window);
      XQueryTree(display, window, &dummy, &parent, &children, &nchildren);

      if (direction == XDO_FIND_PARENTS) {
	//        _xdo_debug(xdo, "searching parents");
        /* Don't care about the children, but we still need to free them */
        if (children != NULL)
          XFree(children);
        window = parent;
      } else if (direction == XDO_FIND_CHILDREN) {
	//        _xdo_debug(xdo, "searching %d children", nchildren);
        unsigned int i = 0;
        int ret;
        done = True; /* recursion should end us */
        for (i = 0; i < nchildren; i++) {
          ret = xdo_window_find_client(display, children[i], &window, direction);
          fprintf(stderr, "findclient: %ld\n", window);
          if (ret == XDO_SUCCESS) {
            *window_ret = window;
            break;
          }
        }
        if (nchildren == 0) {
          return XDO_ERROR;
        }
        if (children != NULL)
          XFree(children);
      } else {
        fprintf(stderr, "Invalid find_client direction (%d)\n", direction);
        *window_ret = 0;
        if (children != NULL)
          XFree(children);
        return XDO_ERROR;
      }
    } else {
      *window_ret = window;
      done = True;
    }
  }
  return XDO_SUCCESS;
}

int xdo_get_window_name(Display *display, Window window, 
                        unsigned char **name_ret, int *name_len_ret,
                        int *name_type) {
  if (atom_NET_WM_NAME == (Atom)-1) {
    atom_NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", False);
  } 
  if (atom_WM_NAME == (Atom)-1) {
    atom_WM_NAME = XInternAtom(display, "WM_NAME", False);
  }
  if (atom_STRING == (Atom)-1) {
    atom_STRING = XInternAtom(display, "STRING", False);
  }
  if (atom_UTF8_STRING == (Atom)-1) {
    atom_UTF8_STRING = XInternAtom(display, "UTF8_STRING", False);
  }

  Atom type;
  int size;
  long nitems;

  /**
   * http://standards.freedesktop.org/wm-spec/1.3/ar01s05.html
   * Prefer _NET_WM_NAME if available, otherwise use WM_NAME
   * If no WM_NAME, set name_ret to NULL and set len to 0
   */

  *name_ret = xdo_getwinprop(display, window, atom_NET_WM_NAME, &nitems,
                             &type, &size);
  if (nitems == 0) {
    *name_ret = xdo_getwinprop(display, window, atom_WM_NAME, &nitems,
                               &type, &size);
  }
  *name_len_ret = nitems;
  *name_type = type;

  return 0;
}

int xdo_get_window_class(Display *display, Window window, 
                        unsigned char **name_ret, int *name_len_ret,
                        int *name_type) {
  if (atom_WM_CLASS == (Atom)-1) {
    atom_WM_CLASS = XInternAtom(display, "WM_CLASS", False);
  }
  if (atom_STRING == (Atom)-1) {
    atom_STRING = XInternAtom(display, "STRING", False);
  }
  if (atom_UTF8_STRING == (Atom)-1) {
    atom_UTF8_STRING = XInternAtom(display, "UTF8_STRING", False);
  }

  Atom type;
  int size;
  long nitems;

  *name_ret = xdo_getwinprop(display, window, atom_WM_CLASS, &nitems,
                             &type, &size);
  *name_len_ret = nitems;
  *name_type = type;

  return 0;
}

int main() {
        time_t idle_time;
        static XScreenSaverInfo *mit_info;
        Display *display;
        int screen;
        if((display=XOpenDisplay(NULL)) == NULL) { return(-1); }
        screen = DefaultScreen(display);
	while (1) {
          mit_info = XScreenSaverAllocInfo();
	  XScreenSaverQueryInfo(display, RootWindow(display,screen), mit_info);
	  idle_time = (mit_info->idle) / 1000;
	  XFree(mit_info);
	  if (idle_time < 120) {
	    Window window;
	    int revert;
	    XGetInputFocus(display, &window, &revert);
	    xdo_window_find_client(display, window, &window, XDO_FIND_PARENTS);
	    unsigned char *name;
	    unsigned char *class;
	    int name_len;
	    int name_type;
	    xdo_get_window_class(display, window, &class, &name_len, &name_type);
	    xdo_get_window_name(display, window, &name, &name_len, &name_type);
	    time_t t = time(NULL);
	    struct tm *tmp = localtime(&t);
	    char timestr[200];
	    strftime(timestr, sizeof(timestr), "%F %T", tmp);
	    FILE *log = fopen("timetracker.csv", "a");
	    fprintf(log, "%s;%d;%s;\"%s\"\n", timestr, idle_time, class, name);
	    fclose(log);
	    printf("%s;%d;%s;\"%s\"\n", timestr, idle_time, class, name);
	    XFree(name);
	  }
	  sleep(5);
	}
        XCloseDisplay(display); 
}
